﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Communication.Lib.Core;
using Communication.Lib.Mode;
using log4net;

namespace Communication.Lib.Protocol
{
    public class ProtocolBI : IProtocolable<BIInfo>
    {
        private static ILog _logger = LogManager.GetLogger(typeof(ProtocolBI));

        private static object _lockobj = new object();
        private static ProtocolBI _instance = null;
        private static List<byte> _bytebuffer;
        private const byte FirstByte = 0x55;
        private const byte SecondByte = 0xff;

        public static ProtocolBI Instance
        {
            get
            {
                if (_instance == null)
                {
                    lock (_lockobj)
                    {
                        _instance = new ProtocolBI();
                    }
                }

                return _instance;
            }
        }

        private const int MinLength = 4;

        private ProtocolBI()
        {
            _bytebuffer = new List<byte>();
        }

        public byte[] EncodeBytes(BIInfo info)
        {
            var res = new List<byte>();
            int length = info.DataLength == 0 ? 1 : 2 + info.DataLength;
            res.Add(FirstByte);
            res.Add(SecondByte);
            res.Add((byte)length);
            res.Add((byte)info.Flag);
            if (info.DataLength != 0)
            {
                res.Add((byte)info.DataLength);
                res.AddRange(Encoding.UTF8.GetBytes(info.Data));
            }
            return res.ToArray();
        }

        public BIInfo DecodeData()
        {
            byte[] toDeBytes = GetBytesFromBuffer();
            if (toDeBytes == null || toDeBytes.Length < MinLength)
            {
                return null;
            }
            return DecodeData(toDeBytes);
        }

        public void AddBytes(byte[] bytes)
        {
            if (_bytebuffer.Count > 800) _bytebuffer.Clear();
            _bytebuffer.AddRange(bytes);
            new Task(() =>
            {
                var s = bytes.FormatAsHex();
                _logger.Debug($"BI decode databytes: {s} ");
            }).Start();
        }

        private BIInfo DecodeData(byte[] toDeBytes)
        {
            BIInfo info = new BIInfo();
            info.Flag = (BiFlag)toDeBytes[3];
            try
            {
                if (Convert.ToInt32(toDeBytes[2]) > 1)
                {
                    int length = Convert.ToInt32(toDeBytes[4]);
                    info.Data = Encoding.UTF8.GetString(toDeBytes.Skip(5).Take(length).ToArray());
                }
            }
            catch (Exception ex)
            {
                _logger.Error($"DecodeData Error.ex:{ex}");
                return null;
            }
            return info;
        }

        #region 数据缓存

        private byte[] GetBytesFromBuffer()
        {
            byte[] res = null;
            if (_bytebuffer.Count >= MinLength)
            {
                int index = _bytebuffer.IndexOf(FirstByte, 0);
                if (index > -1 && index <= _bytebuffer.Count - MinLength)//有帧头 可截取
                {
                    if (_bytebuffer[index + 1] == SecondByte) //帧头2字节正常
                    {
                        int msgLength = 3 + Convert.ToInt32(_bytebuffer[index + 2]);
                        if (index <= _bytebuffer.Count - msgLength)
                        {
                            res = _bytebuffer.Skip(index).Take(msgLength).ToArray();
                            _bytebuffer.RemoveRange(0, index + msgLength);
                        }
                    }
                    else //帧头2字节异常  舍弃帧头第一字节
                    {
                        _bytebuffer.RemoveRange(0, index + 1);
                    }
                }
                //没有帧头 返回空
            }
            //不足一帧 返回空
            return res;
        }

        #endregion 数据缓存
    }
}